#include "Calendar.hpp"
#include "AssetManager.hpp"
#include "Notification.hpp"
#include "Util.hpp"
#include <cpp3ds/System/I18n.hpp>
#include <cpp3ds/System/FileSystem.hpp>
#include <TweenEngine/Tween.h>
#include <stdlib.h>

namespace Clock {

Calendar::Calendar()
: m_checkButtons(false)
, m_startedRepeat(false)
{
	m_calendarDial.setOutlineThickness(1);
	m_calendarDial.setOutlineColor(cpp3ds::Color(117, 117, 117));
	m_calendarDial.setFillColor(cpp3ds::Color(158, 158, 158, 64));
	m_calendarDial.setSize(cpp3ds::Vector2f(154.f, 132.f));
	m_calendarDial.setOrigin(m_calendarDial.getLocalBounds().width / 2, m_calendarDial.getLocalBounds().height / 2);
	m_calendarDial.setPosition(290.f, 120.f);

	m_calendarMonthYear = m_calendarDial;
	m_calendarMonthYear.setOrigin(0, 0);
	m_calendarMonthYear.setSize(cpp3ds::Vector2f(m_calendarDial.getSize().x, 22.f));
	m_calendarMonthYear.setPosition(m_calendarDial.getPosition().x - m_calendarDial.getLocalBounds().width / 2, (m_calendarDial.getPosition().y - m_calendarDial.getLocalBounds().height / 2) - m_calendarMonthYear.getLocalBounds().height + 1);

	m_textMonthYear.setFillColor(cpp3ds::Color::Black);
	m_textMonthYear.setCharacterSize(12);
	m_textMonthYear.setPosition(m_calendarMonthYear.getPosition().x + m_calendarMonthYear.getLocalBounds().width / 2, m_calendarMonthYear.getPosition().y + m_calendarMonthYear.getLocalBounds().height / 2);
	m_textMonthYear.useSystemFont();

	m_textLButton.setCharacterSize(12);
	m_textLButton.setFillColor(cpp3ds::Color::Black);
	m_textLButton.useSystemFont();
	m_textLButton.setString("\uE004");
	m_textLButton.setOrigin(m_textLButton.getLocalBounds().width / 2, m_textLButton.getLocalBounds().height / 2);
	m_textLButton.setPosition(m_calendarMonthYear.getPosition().x + 2 + m_textLButton.getLocalBounds().width, m_calendarMonthYear.getPosition().y + m_calendarMonthYear.getLocalBounds().height / 2);

	m_textRButton = m_textLButton;
	m_textRButton.setOrigin(m_textRButton.getLocalBounds().width / 2, m_textRButton.getLocalBounds().height / 2);
	m_textRButton.setPosition((m_calendarMonthYear.getPosition().x + m_calendarMonthYear.getLocalBounds().width) - (2 + m_textLButton.getLocalBounds().width), m_calendarMonthYear.getPosition().y + m_calendarMonthYear.getLocalBounds().height / 2);
	m_textRButton.setString("\uE005");

	time_t t = time(NULL);
	struct tm * timeinfo;
	timeinfo = localtime(&t);

	m_previousDay = m_actualDay = timeinfo->tm_mday;

	init(timeinfo);
}

Calendar::~Calendar()
{

}

void Calendar::draw(cpp3ds::RenderTarget &target, cpp3ds::RenderStates states) const
{
	states.transform *= getTransform();

	target.draw(m_calendarDial, states);

	target.draw(m_calendarMonthYear, states);
	target.draw(m_textMonthYear, states);
	target.draw(m_textLButton, states);
	target.draw(m_textRButton, states);

	for (auto& item : m_calendarBlocks) {
		target.draw(*item, states);
	}
}

void Calendar::update(float delta)
{
	m_tweenManager.update(delta);

	if (m_updateClock.getElapsedTime() >= cpp3ds::seconds(1.f)) {
		m_updateClock.restart();

		time_t t = time(NULL);
		struct tm * timeinfo;
		timeinfo = localtime(&t);

		m_previousDay = m_actualDay;
		m_actualDay = timeinfo->tm_mday;

		if (m_previousDay != m_actualDay)
			init(timeinfo);
	}

	if (m_clockButtonCheck.getElapsedTime() >= cpp3ds::milliseconds(m_startedRepeat ? 500 : 100) && m_checkButtons) {
		m_clockButtonCheck.restart();
		m_startedRepeat = false;

		if (cpp3ds::Keyboard::isKeyDown(cpp3ds::Keyboard::L))
			previous();
		else if (cpp3ds::Keyboard::isKeyDown(cpp3ds::Keyboard::R))
			next();
		else if (cpp3ds::Keyboard::isKeyDown(cpp3ds::Keyboard::ZL))
			previousYear();
		else if (cpp3ds::Keyboard::isKeyDown(cpp3ds::Keyboard::ZR))
			nextYear();
		else
			m_checkButtons = false;
	}
}

void Calendar::processEvent(const cpp3ds::Event& event)
{
	if (event.type == cpp3ds::Event::KeyPressed) {
		switch (event.key.code) {
			case cpp3ds::Keyboard::L: {
				m_startedRepeat = true;
				previous();

				break;
			} case cpp3ds::Keyboard::R: {
				m_startedRepeat = true;
				next();

				break;
			} case cpp3ds::Keyboard::ZL: {
				m_startedRepeat = true;
				previousYear();

				break;
			} case cpp3ds::Keyboard::ZR: {
				m_startedRepeat = true;
				nextYear();

				break;
			} case cpp3ds::Keyboard::B: {
				time_t t = time(NULL);
				struct tm * timeinfo;
				timeinfo = localtime(&t);

				init(timeinfo);
			}
		}
	}
}

void Calendar::init(struct tm * timeinfo)
{
	m_loadedTimeinfo = *timeinfo;

	m_textMonthYear.setString(_("%2i/%i", timeinfo->tm_mon + 1, timeinfo->tm_year + 1900));
	m_textMonthYear.setOrigin(m_textMonthYear.getLocalBounds().width / 2, m_textMonthYear.getLocalBounds().height / 2);

	std::string weekdays[] = {"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"};
	m_calendarBlocks.clear();

	int actualDay = timeinfo->tm_mday;
	timeinfo->tm_mday = 1;
	mktime(timeinfo);
	//printf("Start weekday: %s\n", weekdays[timeinfo->tm_wday].c_str());

	int currentDay = 1;
	int startWeekDay = timeinfo->tm_wday;
	int lastDay = getDaysInMonth(timeinfo->tm_mon + 1, timeinfo->tm_year + 1900);

	int lineNumber = 6;
	if ((startWeekDay == 5 && lastDay > 30) || startWeekDay == 6 && lastDay > 29)
		lineNumber = 7;

	time_t t = time(NULL);
	struct tm * todayTimeinfo;
	todayTimeinfo = localtime(&t);

	int birthDay, birthMonth;
	getBirthday(&birthDay, &birthMonth);

	for (int y = 0; y < lineNumber; ++y) {
		for (int x = 0; x < 7; ++x) {
			std::shared_ptr<CalendarBlock> item(new CalendarBlock());
			m_calendarBlocks.emplace_back(std::move(item));
			CalendarBlock *lastBlockPointer = m_calendarBlocks.back().get();

			if (y == 0) {
				lastBlockPointer->setBlockText(weekdays[x]);
				lastBlockPointer->toggleInverted();
			} else if (y == 1) {
				if (x >= startWeekDay) {
					lastBlockPointer->setBlockText(std::to_string(currentDay));
					currentDay++;
				}
			} else {
				if (currentDay <= lastDay) {
					lastBlockPointer->setBlockText(std::to_string(currentDay));
					currentDay++;
				}
			}
			lastBlockPointer->setPosition((m_calendarDial.getPosition().x - m_calendarDial.getLocalBounds().width / 2) + (x * lastBlockPointer->getSize().x), (m_calendarDial.getPosition().y - m_calendarDial.getLocalBounds().height / 2) + (y * lastBlockPointer->getSize().y));

			int selectedDay = currentDay - 1;
			if (selectedDay == actualDay && todayTimeinfo->tm_mon == timeinfo->tm_mon && todayTimeinfo->tm_year == timeinfo->tm_year)
				lastBlockPointer->toggleSelected();

			if (x == 0)
				lastBlockPointer->setPreset(CalendarBlock::Sunday);
			else if (x == 6)
				lastBlockPointer->setPreset(CalendarBlock::Saturday);

			if (selectedDay == birthDay && timeinfo->tm_mon + 1 == birthMonth) {
				if (lastBlockPointer->isSelected()) {
					lastBlockPointer->setSelectedColor(lastBlockPointer->getSelectedColor() + cpp3ds::Color(255, 152, 0));
				} else {
					lastBlockPointer->toggleSelected();
					lastBlockPointer->setSelectedColor(cpp3ds::Color(255, 152, 0));
				}
			}

			//printf("x:%i, y:%i = %i\n", x, y, (x * 6) + y);
		}
	}
}

void Calendar::previous()
{
	m_checkButtons = true;
	m_clockButtonCheck.restart();

	struct tm pastTime = m_loadedTimeinfo;

	pastTime.tm_mon--;
	if (pastTime.tm_mon < 0) {
		pastTime.tm_mon = 11;
		pastTime.tm_year--;
	}
	init(&pastTime);
}

void Calendar::next()
{
	m_checkButtons = true;
	m_clockButtonCheck.restart();

	struct tm futureTime = m_loadedTimeinfo;

	futureTime.tm_mon++;
	if (futureTime.tm_mon > 11) {
		futureTime.tm_mon = 0;
		futureTime.tm_year++;
	}
	init(&futureTime);
}

void Calendar::previousYear()
{
	m_checkButtons = true;
	m_clockButtonCheck.restart();

	struct tm pastTime = m_loadedTimeinfo;

	pastTime.tm_year--;
	init(&pastTime);
}

void Calendar::nextYear()
{
	m_checkButtons = true;
	m_clockButtonCheck.restart();

	struct tm futureTime = m_loadedTimeinfo;

	futureTime.tm_year++;
	init(&futureTime);
}

} // namespace Clock
